#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <stdlib.h>
#include <iostream>
#include <vector>

enum
{
    OK,
    USAGE_ERR
};

typedef void (*callback_t)();

void Task()
{
    int cnt = 5;
    while(cnt--)
    {
        printf("我是一个子进程, 我在完成Task任务, pid: %d, ppid: %d, cnt: %d\n", getpid(), getppid(), cnt);
        sleep(1);
    }
}

void Hello()
{
    int cnt = 5;
    while(cnt--)
    {
        printf("我是一个子进程, 我在完成Hello任务, pid: %d, ppid: %d, cnt: %d\n", getpid(), getppid(), cnt);
        sleep(1);
    }
}
void CreateTask(int num, std::vector<callback_t>* cbs)
{
    for(int i = 0; i < num; ++i)
    {
        cbs->push_back(Task);
        cbs->push_back(Hello);
    }
}

// 一般而言：
// 输入：const&
// 输出：*
// 输入输出：&
void CreateChildProcess(int num, std::vector<pid_t>* subs, const std::vector<callback_t>& cbs)
{

    for(int i = 0; i < num; ++i)
    {
        pid_t id = fork();
        if(id == 0)
        {
            // child
            cbs[i]();  
            exit(OK);
        }
        // 父进程
        subs->push_back(id);
    }

}

void WaitAllChild(const std::vector<pid_t>& subs)
{
    for(const auto& pid : subs)
    {
        int status = 0;
        pid_t rid = waitpid(pid, &status, 0);
        if(rid > 0)
        {
            printf("子进程：%d Exit， exit_code: %d\n", rid, WEXITSTATUS(status));
        }
    }
    
}

// 启动多进程的方案
// ./myproc 5 --- 我要创建五个子进程
int main(int argc, char* argv[])
{
    if(argc != 2)
    {
        std::cout << "Usage: " << argv[0] << " process_number" << std::endl;
        exit(USAGE_ERR);
    }
    int num = std::stoi(argv[1]);
    std::vector<pid_t> subs;
    std::vector<callback_t> cbs;
    // 为每个子进程创建任务
    CreateTask(num, &cbs);
    // 创建多进程
    CreateChildProcess(num, &subs, cbs);

    // father
    // 等待多进程
    WaitAllChild(subs);
    return OK;
}


//typedef void (*callback_t)();
//
//void PrintLog()
//{
//    std::cout << "printf log" << std::endl;
//}
//
//void SyncDisk()
//{
//    std::cout << "write data to disk" << std::endl;
//}
//
//void WriteDateTOMysql()
//{
//    std::cout << "write data to mysql" << std::endl;
//}
//
////// exit_sig
////#define WIFEXITED(status) (!(status & 0x7F))
////// exit_code
////#define WEXITSTATUS(status) ((status >> 8) & 0xFF)
//
//int main()
//{
//    printf("我是一个父进程：pid: %d, ppid: %d\n", getpid(), getppid());
//
//    std::vector<callback_t> tasks;
//    tasks.push_back(PrintLog);
//    tasks.push_back(SyncDisk);
//    tasks.push_back(WriteDateTOMysql);
//
//
//    pid_t id = fork();
//    if(id < 0)
//    {
//        perror("fork");
//        exit(1);
//    }
//    else if(id == 0)
//    {
//        // child
//        int cnt = 5;
//        while(cnt--)
//        {
//            printf("I am a child process: pid: %d, ppid: %d\n", getpid(), getppid());
//            sleep(1);
//        
//            //int* p = NULL;
//            //*p = 100;
//        }
//        exit(10);
//    }
//    else
//    {
//        while(1)
//        {
//            int status = 0;
//            pid_t rid = waitpid(id, &status, WNOHANG); // 非阻塞检测&&回收
//            if(rid > 0)
//            {
//                printf("wait success! 退出的子进程的pid是：%d, exit_code: %d\n", rid, WEXITSTATUS(status));
//                break;
//            }
//            else if(rid == 0)
//            {
//                printf("子进程正在运行，父进程还需要等待\n");
//                usleep(100000);
//                
//                for(auto& task : tasks)
//                    task();
//            }
//            else
//            {
//                perror("waitpid");
//                break;
//            }
//        }
//        
//            
//
//        //int status = 0;
//        //// 父进程阻塞等待
//        //pid_t rid = waitpid(id, &status, 0);
//        //if(rid > 0)
//        //{
//        //    //int exit_code = (status >> 8) & 0xFF;
//        //    //int exit_sig = status & 0x7F;
//        //    //printf("wait success, 退出的子进程的pid是：%d, exit_code: %d, exit_sig: %d\n", rid, exit_code, exit_sig);
//        //
//        //    if(WIFEXITED(status)) // 判断进程是否正常退出，即信号是否为0
//        //    {
//        //        printf("wait success! 退出的子进程的pid是：%d, exit_code: %d\n", rid, WEXITSTATUS(status));
//        //    }
//        //    else
//        //    {
//        //        printf("子进程是异常退出的\n");
//        //    }
//        //}
//        //else
//        //{
//        //    printf("rid: %d\n", rid);
//        //    perror("wait failed");
//        //}
//    }
//}
